// Semaphore.h: interface for the CSemaphore class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_SEMAPHORE_H__E3674F9A_B00E_49BB_9E12_317E4FCC56D7__INCLUDED_)
#define AFX_SEMAPHORE_H__E3674F9A_B00E_49BB_9E12_317E4FCC56D7__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifdef WIN32
#include <windows.h>
#else
#include <semaphore.h>
#include <pthread.h>
#include <unistd.h>
#endif
#include "osplatform.h"
#include "base.h"

class BASE_API CSemaphore
{
public:
	CSemaphore()
	{
#ifdef WIN32
		m_hSemaphore = NULL;
#endif
	};
	virtual ~CSemaphore()
	{
#ifdef WIN32
		if(m_hSemaphore)
			CloseHandle(m_hSemaphore);
#else
		sem_destroy(&m_hSemaphore);
#endif
	};
	int InitSemaphore(int pshared, unsigned int value, unsigned int max=8192)
	{
#ifdef WIN32
		m_hSemaphore = CreateSemaphoreA(
				NULL, // SD
				value,                          // initial count
				max/*8192*/,                          // maximum count
				NULL                           // object name
			);
		return m_hSemaphore == NULL;
#else
		return sem_init(&m_hSemaphore, 0, value);
#endif
	};
	int signal()
	{
#ifdef WIN32
		return ReleaseSemaphore(m_hSemaphore,1,NULL);
#else
		return sem_post(&m_hSemaphore);
#endif
	};
	int wait()
	{
#ifdef WIN32
		return WAIT_FAILED == WaitForSingleObject(m_hSemaphore,INFINITE);
#else
		return sem_wait(&m_hSemaphore);
#endif
	};
	int wait(int timeout) 
	{
#ifdef WIN32
		DWORD ret;
		ret = WaitForSingleObject(m_hSemaphore,timeout/1000);
		if(ret == WAIT_TIMEOUT || ret == WAIT_FAILED)
			return 1;
		return 0;
#else
		if(timeout == 0)
			return 1;
		m_dwTimeOut = timeout;
		while(m_dwTimeOut > 0)
		{
			if(sem_trywait(&m_hSemaphore) == -1)
				m_dwTimeOut --;
			else
				return 0;		
		}
		return 1;
	
#endif
	}

	//yxy:2006-10-08 for radius_server 
	int trywait() 
	{
#ifdef WIN32
		DWORD ret;
		ret = WaitForSingleObject(m_hSemaphore,0);
		if(ret == WAIT_FAILED || ret == WAIT_TIMEOUT)
			return 1;//sem count is 0, return immediately
		return 0;//sem has none-zero count ,decreaced ok
#else
		if(sem_trywait(&m_hSemaphore)==-1)
			return 1;//sem count is 0, return immediately
		return 0;//sem has none-zero count ,decreaced ok 
	
#endif
	}
	//end
private:

#ifdef WIN32
	HANDLE	m_hSemaphore;
#else
	sem_t	m_hSemaphore;
#endif
	int		m_dwTimeOut;
};


class BASE_API Event{
private:
#ifdef WIN32

	HANDLE m_hEvent;
#else
	pthread_cond_t m_hEvent;
	pthread_mutex_t m_hMutex;
#endif
public:
	Event()
	{
#ifdef WIN32
		m_hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
#else
	//	m_hEvent = PTHREAD_COND_INITIALIZER;
	//	m_hMutex = PTHREAD_MUTEX_INITIALIZER;
		pthread_cond_init(&m_hEvent,NULL);
		pthread_mutex_init(&m_hMutex,NULL);
#endif
	};

	~Event()
	{
#ifdef WIN32
		CloseHandle(m_hEvent);
#else
		pthread_cond_destroy(&m_hEvent);
		pthread_mutex_destroy(&m_hMutex);
#endif
	};

	int Wait()
	{
#ifdef WIN32
		if(m_hEvent == 0)
			return -1;

		WaitForSingleObject(m_hEvent,INFINITE);
#else	
		pthread_cond_wait(&m_hEvent,&m_hMutex);
#endif
		return 0;
	}
	
	int SetEvent()
	{
#ifdef WIN32
		if(m_hEvent == 0)
			return -1;
		::SetEvent(m_hEvent);
#else
		pthread_cond_signal(&m_hEvent);
#endif
		return 0;
	}	
	bool WaitForTime(DWORD time)
	{
#ifdef WIN32
		if(m_hEvent == 0)
			return false;
		//printf("time=%d\n",time);
		ResetEvent(m_hEvent);
// 		if(time > 500)
// 		{
// 			time = 1;
// 			//printf("time error               error\n");
// 		}		
		return (WAIT_OBJECT_0 == WaitForSingleObject(m_hEvent,time));
#else
		struct timespec abstime;
		struct timeval t;
		int res;
		gettimeofday(&t,NULL);
		abstime.tv_sec = t.tv_sec + (t.tv_usec + time*1000)/1000000;
		abstime.tv_nsec = (t.tv_usec * 1000 + time * 1000000)%1000000000;
		pthread_mutex_lock(&m_hMutex);
		res = pthread_cond_timedwait(&m_hEvent,&m_hMutex,&abstime);
		pthread_mutex_unlock(&m_hMutex);

		return (0 == res);
#endif		
	}
};

class CMutex
{
    public:

        CMutex();
        ~CMutex();

        inline void Lock();
        inline void Unlock();
        
        // Returns true on successful grab of the lock, false on failure
        inline bool TryLock();

    private:

#ifdef WIN32
        CRITICAL_SECTION fMutex;
        
        pthread_t fHolder;
        UINT      fHolderCount;
        
#else
        pthread_mutex_t fMutex;
        // These two platforms don't implement pthreads recursive mutexes, so
        // we have to do it manually
        pthread_t   fHolder;
        UINT      fHolderCount;
#endif

        void        RecursiveLock();
        void        RecursiveUnlock();
        bool      RecursiveTryLock();

};

class   CMutexLocker
{
    public:

        CMutexLocker(CMutex *inMutexP) : fMutex(inMutexP) { if (fMutex != NULL) fMutex->Lock(); }
        ~CMutexLocker() {  if (fMutex != NULL) fMutex->Unlock(); }
        
        void Lock()         { if (fMutex != NULL) fMutex->Lock(); }
        void Unlock()       { if (fMutex != NULL) fMutex->Unlock(); }
        
    private:

        CMutex*    fMutex;
};

void CMutex::Lock()
{

    this->RecursiveLock();

}

void CMutex::Unlock()
{
    this->RecursiveUnlock();
}

bool CMutex::TryLock()
{
    return this->RecursiveTryLock();
}



#endif // !defined(AFX_SEMAPHORE_H__E3674F9A_B00E_49BB_9E12_317E4FCC56D7__INCLUDED_)
